unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes,
  Graphics, Controls, Forms, Dialogs, StdCtrls,
  Sockets, Menus, ShellAPI, DateUtils,  ExtCtrls,

  msglogwnd,
  strings,
  unit3,
//  network,
  General_code,
  OSinfo,settings,
  irc_protocol,
  Time; //auto generated file


  procedure read_irc     (data : WideString);
  procedure read_privmsg (data : WideString);
  procedure irc_say(user: WideString; data: WideString);
  procedure irc_sendln(data:WideString);


  // old single channel code
  function idle_time(user:WideString):TDateTime;
  procedure say_seen(user:WideString ;data: WideString);
  function nr_seen(user:WideString):integer;
  procedure add_seen(user: WideString; data:WideString);
  procedure say_idle(target: WideString; user: WideString);

  // new code for multi channel support
  procedure talking_user(channel:WideString; user:WideString; text:WideString);
  procedure part_channel(channel:WideString);
  procedure join_channel(channel:WideString);
  procedure part_user(channel:WideString; user: WideString);
  procedure join_user(channel:WideString; user: WideString; hostname: WideString);
  procedure join_newuser(channel:WideString; user: WideString; hostname: WideString);
  function  nr_user(channel:WideString;user:WideString):integer;
  function  nr_channel(channel:WideString):integer;
  function idleling_user(channel:WideString; user:WideString):TDateTime;



type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Settings1: TMenuItem;
    Setting1: TMenuItem;
    Connect1: TMenuItem;
    Exit1: TMenuItem;
    Disconnect1: TMenuItem;
    Memo1: TMemo;
    Edit1: TEdit;
    Label1: TLabel;
    Help1: TMenuItem;
    About1: TMenuItem;
    Pinger: TTimer;
    ChatLog1: TMenuItem;
    TcpClient1: TTcpClient;
    TcpClient2: TTcpClient;
    TcpServer1: TTcpServer;
    procedure Setting1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Connect1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);

   //tray code
    procedure TrayMessage(var Msg: TMessage); message WM_USER;

    procedure Disconnect1Click(Sender: TObject);
    procedure Exit1Click(Sender: TObject);
    procedure About1Click(Sender: TObject);
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
    procedure PingerTimer(Sender: TObject);
    procedure Memo1Change(Sender: TObject);
    procedure ChatLog1Click(Sender: TObject);


  private

    // tray code van site
    TrayIconData: TNotifyIconData;

    { Private declarations }
  public
    { Public declarations }
  end;

    type
  TReceive = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;




var
  Form1: TForm1;

implementation


{$R *.dfm}

procedure TForm1.Setting1Click(Sender: TObject);
  begin
    Form2.ShowModal;
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin

{
//// tray code van site
///////////////////////
  with TrayIconData do
  begin
    cbSize := SizeOf(TrayIconData);
    Wnd := Handle;
    uID := 0;
    uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
    uCallbackMessage := WM_USER;
    hIcon := Application.Icon.Handle;
    StrPCopy(szTip, Application.Title);
  end;

  Shell_NotifyIcon(NIM_ADD, @TrayIconData);

///////////
}








///////////////////
// debug version
// replace this with file code
//////////////////
//irc_server  := 'irc.chat4all.org';
irc_server  := '10.0.0.60';
irc_port    := '6667';
irc_channel := '#blaatcoding';
//irc_channel := '#blaatschaap';
irc_nick    := 'DarkShadow';
irc_nickpass:= 'Blaat';
///////////////





TimeSeparator   := ':';
DateSeparator   := '-';
ShortDateFormat := 'dd/mm/yyyy' ;
LongTimeFormat  := 'hh:nn:ss'   ;
bot_version := DateTimeToStr(CompileTime);
Memo1.Lines.Add('BlaatBot '+bot_version+ ' started.');
Memo1.Lines.Add('OS Detected: '+GetOSNAME() + ' (' +GetOSSP() +') '+GetOSVersion() );



end;

procedure TReceive.Execute;
var
  temp         : char;
  receiveddata : String;
begin
  repeat
    repeat
      if Form1.TcpClient1.WaitForData(1) then
      begin
        Form1.TcpClient1.ReceiveBuf(temp,1);
        if not ( (temp = #$0) or (temp = #$D) or (temp = #$A) )
          then receiveddata := receiveddata + temp;
        end;
    until (temp = #$0) or (temp = #$D) or (temp = #$A);

if not (receiveddata = '') then read_irc(receiveddata);
//    ShowMessage(receiveddata);
    receiveddata := '';
  until NOT Form1.TcpClient1.Connected;


end;



procedure TForm1.Connect1Click(Sender: TObject);
begin
  TcpClient1.RemoteHost := Form2.Server.Text;
  TcpClient1.RemotePort := Form2.Port.Text;
  Memo1.Lines.Add('Connecting to ' +
                Form2.Server.Text + ' port ' + Form2.Port.Text);
  if (Form1.TcpClient1.Connect) then
    begin
      Memo1.Lines.Add('Connected...');
      starttime := Now;
      TReceive.Create(false);
      irc_sendln('NICK ' + Form2.Nick.Text);
      irc_sendln('USER BlaatBot2006 BlaatBot2006 '+ Form2.Server.Text + ' :BlaatBot2006');
    end else Memo1.Lines.Add('Connection failed.');
end;

procedure read_privmsg(data : WideString);
var target : WideString;  count : integer;
begin

  if not (readparams(data,2,false) = irc_nick) then
//    assign((logfile[nr_channel((readparams(data,2,false)))]),(readparams(data,2,false)));
try
//    reset(logfile[nr_channel((readparams(data,2,false)))]);
//    append(logfile[nr_channel((readparams(data,2,false)))]);
    writeln(logfile[nr_channel(readparams(data,2,false))],
    DateTimeToStr(Now)                  + ' ' +
    ReadParams(data,2,false)            + ' ' +
    ReadUser(readparams(data,0,false))  + ' ' +
    CleanTXT(readparams(data,3,true)));
except
FOrm1.Memo1.lines.add (    readparams(data,2,false)            + ' ' +
    ReadUser(readparams(data,0,false))  + ' ' +
    CleanTXT(readparams(data,3,true))  + ' :writelog failed' );
end;

{
Form4.Memo1.Lines.Add(
    DateTimeToStr(Now)                  + ' ' +
    ReadParams(data,2,false)            + ' ' +
    ReadUser(readparams(data,0,false))  + ' ' +
    CleanTXT(readparams(data,3,true)));
 }





    if  ( readparams(data,2,false) = irc_nick) then
    target := ReadUser(readparams(data,0,false))
    else
    target := readparams(data,2,false);







//Form1.Memo1.Lines.Add(ReadHost(readparams(data,0,false)));
//Form1.Memo1.Lines.Add(ReadUser(readparams(data,0,false)));


add_seen(ReadUser(readparams(data,0,false)), CleanTXT(readparams(data,3,true)));
talking_user(target,ReadUser(readparams(data,0,false)), CleanTXT(readparams(data,3,true)));




// CTCP VERSION RESPONSE
if ( CleanTXT(readparams(data,3,false)) = (CHR(1)+'VERSION'+CHR(1)) ) then
  begin
    irc_sendln('NOTICE ' +
          ReadUser(readparams(data,0,false)) + ' :' +
          CHR($01) + 'VERSION BlaatBot 2006 '+bot_version+ CHR($01));
    irc_sendln('NOTICE ' +
          ReadUser(readparams(data,0,false)) + ' :' +
          CHR($01) + 'VERSION '+GetOSName()+GetOSVersion()+ CHR($01));


    Form1.Memo1.Lines.Add('Received CTCP VERSION from '+
          ReadUser(readparams(data,0,false)));
  end;
//


if (readparams(CleanTXT(readparams(data,3,true)),0,false) = '!lag' )
    then
    irc_say(target,FloatToStr(irclag));


if (readparams(CleanTXT(readparams(data,3,true)),0,false) = '!idle' )
    then begin
      count := 3;
      repeat
        irc_say(target, userdata[nr_channel(target)][count][1] +' '+
        TimeToStr(idleling_user(target,userdata[nr_channel(target)][count][1])));
        count := count + 1;
      until userdata[nr_channel(target)][count][1] = '';

      end;



if (readparams(CleanTXT(readparams(data,3,false)),0,false) = '!test' )
    then
    irc_say(target,'Mooooo');

if (readparams(CleanTXT(readparams(data,3,false)),0,false) = '!join' )
    then
    begin
    irc_sendln('JOIN '+ readparams(CleanTXT(readparams(data,3,true)),1,false));
    Form1.Memo1.Lines.Add('Joining '+ readparams(CleanTXT(readparams(data,3,true)),1,false));
    end;

if (readparams(CleanTXT(readparams(data,3,false)),0,false) = '!part' )
    then
    begin
    irc_sendln('PART '+ readparams(CleanTXT(readparams(data,3,true)),1,false));
    Form1.Memo1.Lines.Add('Leaving '+ readparams(CleanTXT(readparams(data,3,true)),1,false));
    end;



if (readparams(CleanTXT(readparams(data,3,false)),0,false) = '!uptime' )
    then
    irc_say(target, 'Uptime is '+  TimeToStr(Now - Starttime));

if (readparams(CleanTXT(readparams(data,3,false)),0,false) = '!lseen' )
    then
    say_seen(target, readparams(CleanTXT(readparams(data,3,true)),1,false));

if (readparams(CleanTXT(readparams(data,3,false)),0,false) = '!oidle' )
    then
    say_idle(target, readparams(CleanTXT(readparams(data,3,true)),1,false));


if (readparams(CleanTXT(readparams(data,3,false)),0,false) = '!raw' )
    then
    irc_sendln((readparams(CleanTXT(readparams(data,3,true)),1,true)));



end;


procedure irc_say(user: WideString; data: WideString);
begin
  irc_sendln('PRIVMSG '+user+' :'+data);

end;

function nr_seen(user:WideString):integer;
var count : integer;
begin
  result := 0;
  count := 1;
  repeat
  if AnsiLowerCase(user) = AnsiLowerCase( lseen[count][1] ) then
  result := count;
  count := count + 1;
  until lseen[count][1] = '';
  if result = 0 then result := count;

end;


function idle_time(user:WideString):TDateTime;
begin
if NOT ( lseen[nr_seen(user)][1] = '' ) then
  result := StrToDateTime(lseen[nr_seen(user)][2]) - Now ;
end;

procedure say_idle(target: WideString; user: WideString);
begin
  if NOT ( lseen[nr_seen(user)][1] = '' ) then
      irc_say(target,'Idle time for '+ user + ' is ' +TimeToStr(idle_time(user)))
  else
      irc_say(target,'Idle time for user '+user+' unknown.');
end;


procedure add_seen(user: WideString; data:WideString);
begin
  lseen[nr_seen(user)][1] := user ;
  lseen[nr_seen(user)][2] := DateTimeToStr(Now);
  lseen[nr_seen(user)][3] := data ;
end;

procedure say_seen(user:WideString ;data: WideString);
begin
  if lseen[nr_seen(data)][1]='' then
  irc_say(user,'User '+ data +' has not been seen')
  else
  irc_say(user,'User '+ data +' has last been seen on '+
  lseen[nr_seen(data)][2] + ' saying '+lseen[nr_seen(data)][3]);
end;

procedure irc_sendln(data:WideString);
begin
  Form1.TcpClient1.Sendln(data);
end;

procedure  read_irc(data : WideString);
begin
  Form4.Memo1.Lines.Add(data);
   if ReadParams(data,1,false) = 'PONG' then begin

      PONG := Now;
      irclag := ( 1000 * SecondOf(PING - PONG) + MilliSecondOf(PING - PONG) );
      if irclag > 1000 then irc_say(irc_channel,'Warning : lag is ' + FloatToStr(irclag) );
      //      Form1.Memo1.Lines.Add(FloatToStr(irclag));
      end;

  if readparams(data,0,false)= 'PING' then
      begin
        Form1.Memo1.Lines.Add(data);
        irc_sendln('PONG ' + readparams(data,1,true));
      end;

  if readparams(data,1,false)= '376' then
    begin
      Form1.Memo1.Lines.Add('Joining '+settings.Form2.Channel.Text);
       irc_sendln ('JOIN '+ irc_channel);
       irc_say('NickServ','identify  '+irc_nickpass);

    end;


   if ReadParams(data,1,false) = 'JOIN' then begin
      if  AnsiLowerCase( ReadUser(ReadParams(data,0,false))) = (AnsiLowerCase(irc_nick))
      then begin // bot joins channel
        Form1.Memo1.Lines.Add('Joined '+ CleanTXT(ReadParams(data,2,false)));
        join_channel(CleanTXT(ReadParams(data,2,false)));

        assign(logfile
          [nr_channel(CleanTXT(ReadParams(data,2,false)))],
          CleanTXT(ReadParams(data,2,false)) +'.log');


if FileExists(
CleanTXT(ReadParams(data,2,false)) + '.log' ) then begin

//        try
          append (logfile
            [nr_channel(CleanTXT(ReadParams(data,2,false)))]);
            Form1.Memo1.Lines.Add('A');
end else begin
                rewrite (logfile
          [nr_channel(CleanTXT(ReadParams(data,2,false)))]);
            Form1.Memo1.Lines.Add('R');
        end;


        irc_sendln ('WHO ' + CleanTXT(ReadParams(data,2,false)));
        irc_sendln ('MODE ' + CleanTXT(ReadParams(data,2,false)));
        end else begin // user joins channel
        join_newuser(CleanTXT(ReadParams(data,2,false)),ReadUser(ReadParams(data,0,false)),ReadParams(data,5,false));

        end;
   end;






  if readparams(data,1,false)= '352' then
    begin
    join_user(ReadParams(data,3,false),ReadParams(data,7,false),ReadParams(data,5,false));
    end;












  if readparams(data,1,false) = 'PRIVMSG' then
    read_privmsg(data);


end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 Shell_NotifyIcon(NIM_DELETE, @TrayIconData);

try CloseFile(logfile[1]); except end;
try  CloseFile(logfile[2]);except end;
try  CloseFile(logfile[3]);except end;
try  CloseFile(logfile[4]);except end;
try  CloseFile(logfile[5]);except end;
try  CloseFile(logfile[6]);except end;
try  CloseFile(logfile[7]);except end;
try  CloseFile(logfile[8]);except end;
try  CloseFile(logfile[9]);except end;
try  CloseFile(logfile[10]);except end;
try  CloseFile(logfile[11]);except end;





end;

/// tray code van site
procedure TForm1.TrayMessage(var Msg: TMessage);
begin
  case Msg.lParam of
    WM_LBUTTONDOWN:
    begin
        Form1.Show;
    end;
    WM_RBUTTONDOWN:
    begin
        Form1.Hide;
    end;
  end;

end;



procedure TForm1.Disconnect1Click(Sender: TObject);
begin
  irc_sendln('QUIT BlaatBot Disconecting');
Form1.TcpClient1.Disconnect;
Memo1.Lines.Add('Disconnected...');
end;

procedure TForm1.Exit1Click(Sender: TObject);
begin
Disconnect1.Click;
Self.Close;
end;

procedure TForm1.About1Click(Sender: TObject);
begin
ShowMessage('BlaatSchaap IRC bot 2006 Edition : version '+bot_version);
end;

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #13 then
    begin
      Key := #0;
      read_privmsg(':botadmin!localhost PRIVMSG '+irc_nick+' :'+Edit1.Text);
      Edit1.Clear;
      end;
end;

procedure TForm1.PingerTimer(Sender: TObject);

begin
PING := Now;
irc_sendln('PING Mooo');

end;




function nr_channel(channel:WideString):integer;
  var count : integer;
  begin
    result := 0;
    count := 1;
    repeat
      if channel = userdata[count][1][1] then
          result := count;
      count := count + 1;
    until userdata[count][1][1] = '';
    if result = 0 then result := count;

  end;

function nr_user(channel:WideString;user:WideString):integer;
  var count : integer;
  begin
    result := 0;
    count := 2;
    repeat
      if AnsiLowerCase(user) = AnsiLowerCase( userdata[nr_channel(channel)][count][1]) then
        result := count;
      count := count + 1;
    until userdata[nr_channel(channel)][count][1] = '';
    if result = 0 then result := count;
end;

procedure join_user(channel:WideString; user: WideString; hostname: WideString);
  begin
    userdata[nr_channel(channel)][nr_user(channel,user)][1] := user;
    userdata[nr_channel(channel)][nr_user(channel,user)][2] := 'inchannel';
    userdata[nr_channel(channel)][nr_user(channel,user)][6] := hostname;
//  Form1.Memo1.Lines.Add(user);
end;

procedure join_newuser(channel:WideString; user: WideString; hostname: WideString);
  begin
    userdata[nr_channel(channel)][nr_user(channel,user)][1] := user;
    userdata[nr_channel(channel)][nr_user(channel,user)][2] := 'joined';
    userdata[nr_channel(channel)][nr_user(channel,user)][3] := DateTimeToStr(Now);
    userdata[nr_channel(channel)][nr_user(channel,user)][6] := hostname;
    Form1.Memo1.Lines.Add(user + ' joined');
    irc_say(channel, 'Welcome '+user+ ' to '+ channel);

  end;

procedure part_user(channel:WideString; user: WideString);
  begin
    userdata[nr_channel(channel)][nr_user(channel,user)][2] := 'left';
    userdata[nr_channel(channel)][nr_user(channel,user)][3] := DateTimeToStr(Now);
  end;

procedure talking_user(channel:WideString; user:WideString; text:WideString);
  begin
    userdata[nr_channel(channel)][nr_user(channel,user)][4] := DateTimeToStr(Now);
    userdata[nr_channel(channel)][nr_user(channel,user)][5] := text;
  end;

function idleling_user(channel:WideString; user:WideString):TDateTime;
  begin

//  Form1.Memo1.Lines.Add('Channel : '+ channel + ' User : '+ user);
    if NOT (  userdata[nr_channel(channel)][nr_user(channel,user)][4] = '') then
      result := Now - StrToDateTime(userdata[nr_channel(channel)][nr_user(channel,user)][4]);
//  Form1.Memo1.Lines.Add(TimeToStr(result));
  end;

procedure join_channel(channel:WideString);
  begin

    userdata[nr_channel(channel)][1][1] := channel;
    userdata[nr_channel(channel)][1][2] := 'joined';
    userdata[nr_channel(channel)][1][3] := DateTimeToStr(Now);
    //debug//
    Form1.Memo1.Lines.Add( IntToStr(nr_channel(channel)) + ' '+ userdata[nr_channel(channel)][1][1]);
  end;

procedure part_channel(channel:WideString);
  begin
    userdata[nr_channel(channel)][1][1] := channel;
    userdata[nr_channel(channel)][1][2] := 'left';
    userdata[nr_channel(channel)][1][3] := DateTimeToStr(Now);
  end;

procedure TForm1.Memo1Change(Sender: TObject);
begin
Memo1.Lines.SaveToFile('log.txt');
end;

procedure TForm1.ChatLog1Click(Sender: TObject);
begin
Form4.Show;
end;

end.
